package world.map;

import java.util.HashSet;
import java.util.Set;

import world.BlockTypeEnum;
import world.Chunk;
import world.ChunkBlock;
import world.World;

public class ChunkProviderFlat extends ChunkProvider {
	private static final int RADIUS = 4;
	
	public ChunkProviderFlat(World world) {
		this.world = world;
		this.chunkMap = world.getChunks();
	}

	@Override
	public boolean exist(int indexX, int indexZ) {
		int key = Chunk.getID(indexX, indexZ);
		return chunkMap.get(key)!=null;
	}

	@Override
	public Chunk create(int indexX, int indexZ) {
		Chunk chunk = new Chunk(this.world, indexX, indexZ);
		chunk.setBlocks(createBlocks(chunk));
		return chunk;
	}

	private ChunkBlock[][][] createBlocks(Chunk chunk) {
		int sizeX = Chunk.SIZE;
		int sizeY = Chunk.SIZE;
		int sizeZ = Chunk.SIZE;
		ChunkBlock[][][] blocks = new ChunkBlock[sizeX][sizeY][sizeZ];
		for (int i = 0; i < sizeX; i++) {
			for (int j = 0; j < sizeY; j++) {
				for (int k = 0; k < sizeZ; k++) {
					ChunkBlock b = new ChunkBlock(BlockTypeEnum.BRICK.getID(), i, j, k);
					blocks[i][j][k] = b;
					b.createVertexes();
				}
			}
		}
		return blocks;
	}	
	
	public Chunk loadChunks(float posX, float posY, float posZ) {
		int chunkIndexX =  (int)Math.floor(posX / Chunk.SIZE);
		int chunkIndexZ = (int)Math.floor(posZ /  Chunk.SIZE);
		return loadChunks(chunkIndexX, chunkIndexZ);
	}	
	
	public Chunk loadChunks(int chunkIndexX, int chunkIndexZ) {
		int currentKey = Chunk.getID(chunkIndexX, chunkIndexZ);
		Chunk currentChunk = chunkMap.get(currentKey);
		if (currentChunk == null) {
			currentChunk = loadChunk(chunkIndexX, chunkIndexZ);
		}
		
		int r = RADIUS;
		for (int i = -r; i <= r; i++) {
			for (int j = -r; j <= r; j++) {
				if (i == 0 && j == 0) {
					continue;
				}

				int key = Chunk.getID(chunkIndexX + i, chunkIndexZ + j);
				Chunk chunk = chunkMap.get(key);
				if (chunk == null) {
					loadChunk(chunkIndexX + i, chunkIndexZ + j);
				}
			}
		}

		Set<Integer> chunksTobeRemoved = new HashSet<Integer>();
		for (Chunk chunk : chunkMap.values()) {
			int xRadius = Math.abs(chunk.getIndexX() - chunkIndexX);
			int zRadius = Math.abs(chunk.getIndexZ() - chunkIndexZ);

			if (xRadius >RADIUS ||zRadius >RADIUS) {
				chunksTobeRemoved.add(Chunk.getID(chunk.getIndexX(), chunk.getIndexZ()));
			}
		}
		
		for(Integer key: chunksTobeRemoved){
			chunkMap.remove(key);
		}

		return chunkMap.get(currentKey);
	}
	
	
	public Chunk loadChunk(int indexX, int indexZ) {
		if(exist(indexX, indexZ)){
			int key = Chunk.getID(indexX, indexZ);
			return chunkMap.get(key);
		}		

		if (indexX > Short.MAX_VALUE || indexX < Short.MIN_VALUE) {
			return null;
		}
		if (indexZ > Short.MAX_VALUE || indexZ < Short.MIN_VALUE) {
			return null;
		}
		Chunk chunk = create(indexX, indexZ);
		chunk.buildRenderData();
		chunkMap.put(chunk.getID(), chunk);
		return chunk;
	}
}
